/*
-------------------------------------------------------------------
BIE is Copyright 2001-2003 Brunswick Corp.
-------------------------------------------------------------------
Please read the legal notices (docs/legal.txt) and the license
(docs/bie_license.txt) that came with this distribution before using
this software.
-------------------------------------------------------------------
*/
package com.webdeninteractive.sbie.util;

import java.lang.ClassLoader;
import java.util.Map;
import java.util.HashMap;

/** 
 * Abstract class implementing the basic functionality of a factory 
 * which generates named classes.
 * <p>
 * Classes are mapped to names by calling <code>register</code>, and 
 * are created with <code>makeMappedObject</code>.
 * <p>
 * Reasons vary for wanting to create objects by a name mapping,
 * rather than by class name.  As an example an application may wish
 * to abstract service configurations away from implementation
 * classes.
 *
 * @author gfast
 * @version $Id: MappedObjectFactoryBase.java,v 1.1.1.1 2003/05/20 16:56:49 gdf Exp $ 
 */
public abstract class MappedObjectFactoryBase {

    /** ClassLoader to be used to create classes. */
    protected ClassLoader loader;

    /** Stores the mapping between object names and implementing class names.
     *  See <code>initializeMap</code> to change the default implementation.
     */
    protected Map map;


    /** This constructor calls <code>initializeMap</code> to set up the map.
     * @param loader ClassLoader to use to create classes.
     */
    public MappedObjectFactoryBase( ClassLoader loader ) {
        this.loader = loader;
        this.initializeMap();
    }


    /** The default implementation of MappedObjectFactoryBase uses
     *  a HashMap for the name/classname mapping.
     *  If you wish to use another implementation, override this method
     *  and set <code>map</code> appropriately.
     */
    protected void initializeMap() {
        this.map = new HashMap();
    }

    
    /** Register a name -> class name mapping.
     * @throws IllegalArgumentException if the map contains name already.
     */
    public void register( String name, String className )
        throws IllegalArgumentException
    {
        if ( map.containsKey(name) ) {
            throw new IllegalArgumentException( "Mapping already contains a '"
                                                 + name + "' key" );
        }
        map.put(name, className);
    }


    /** Delete a name->classname mapping. */
    public void unregister( String name ) {
        Object ignored = map.remove(name);
    }


    /** Create an object of the type mapped to the given name. */
    public Object makeMappedObject( String name ) 
        throws ClassNotFoundException, InstantiationException, IllegalAccessException
    {
        String className = (String)map.get(name);
        if ( className==null ) {
            throw new ClassNotFoundException("No class is mapped to the name '" + name + "'");
        }
        return loader.loadClass(className).newInstance();
    }        

}
